import { memo, useState, useEffect, useCallback, useRef } from 'react';
import { createPortal } from 'react-dom';
import { Space } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import type { Props, TipConfig } from './interface';

import styles from './index.module.scss';

let diffViewport;

/** 边距 */
const margin = 10;

/**
 * 漫游式引导
 */
function Tour(props: Props) {
  const { open, onClose, steps } = props;

  // 当前处于哪一步
  const [current, setCurrent] = useState(0);
  // 引导信息配置
  const [tipConfig, setTipConfig] = useState({} as TipConfig);
  const { className, style } = tipConfig;

  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    diffViewport = document.querySelector('.diffViewport');
    if (diffViewport) diffViewport.classList.add(styles.hide);
  }, []);

  useEffect(() => {
    open ? handleTour(0) : reset();
  }, [open]);

  /**
   * 检测是否碰撞边界
   */
  const handleDetect = useCallback((dom: HTMLDivElement, x: number) => {
    const { top, left, width, height, right, bottom } = dom.getBoundingClientRect();
    // 目前只写了右边边界碰撞检测
    const rightDistance = x + width / 2 - innerWidth;
    if (rightDistance >= 0) return `${x - rightDistance - margin}px`;
    return `${x}px`;
  }, []);

  /**
   * 处理引导
   */
  const handleTour = useCallback(
    (index = 0) => {
      const { desc, target, placement } = steps[index];
      const dom = ref.current;
      if (!target || !dom) return;
      const descRef = dom.querySelector('#tour-desc');
      if (!descRef) return;
      // 手动填充描述
      descRef.innerHTML = desc;
      // 取消上次元素的高亮
      steps[current].target?.classList.remove(styles.tourStep);
      // 高亮当前元素
      target.classList.add(styles.tourStep);
      // 获取当前元素的位置
      const { top, left, width, height } = target.getBoundingClientRect();
      // 计算当前元素的中心轴
      const x = handleDetect(dom, left + width / 2);
      const y = `${top + height / 2}px`;
      // 位置配置
      const mapConfig = {
        left: { '--tip-top': y, '--tip-left': `${left - margin}px` },
        right: { '--tip-top': y, '--tip-left': `${left + width + margin}px` },
        top: { '--tip-left': x, '--tip-top': `${top - margin}px` },
        bottom: { '--tip-left': x, '--tip-top': `${top + height + margin}px` },
      };
      // 更新位置信息
      setTipConfig({ className: placement, style: mapConfig[placement] });
      setCurrent(index);
    },
    [current, steps],
  );

  // 重置引导
  const reset = useCallback((hasCallback?: boolean) => {
    if (diffViewport) diffViewport.classList.remove(styles.hide);
    setCurrent(0);
    if (hasCallback) onClose(false);
  }, []);

  return createPortal(
    <div x-class={[styles.tour, { [styles.open]: open }]}>
      <div x-class={[styles.tip, styles[className]]} ref={ref} style={style}>
        <Space size={20} direction="vertical" align="end">
          <Space size={15}>
            {/* {desc} */}
            <div id="tour-desc" />
            <CloseOutlined className={styles.close} onClick={() => reset(true)} />
          </Space>
          <Space className={styles.btns} size={10}>
            <div x-if={current > 0} className={styles.prev} onClick={() => handleTour(current - 1)}>
              上一步
            </div>
            <div x-if={current < steps.length - 1} className={styles.next} onClick={() => handleTour(current + 1)}>
              下一步
            </div>
          </Space>
        </Space>
      </div>
    </div>,
    document.body,
  );
}

/**
 * 漫游式引导
 */
export default memo(Tour);
